package com.healthdata.entity;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;

public class NaiveBayesMissingValueFiller {
    private int cNo;                 // 待填充列号
    private Integer[] exp;           // 依赖列号数组
    private List<String> possibleValues; // 可能的填充值

    // 初始化：读取填充配置信息
    public void init(String configFilePath) throws IOException {
        try (BufferedReader br = new BufferedReader(new FileReader(configFilePath))) {
            String line;
            possibleValues = new ArrayList<>();

            while ((line = br.readLine()) != null) {
                if (line.contains("#")) {
                    // 解析列号配置
                    String[] parts = line.split("#");
                    cNo = Integer.parseInt(parts[0]);

                    String[] depCols = parts[1].split(",");
                    exp = new Integer[depCols.length];
                    for (int i = 0; i < depCols.length; i++) {
                        exp[i] = Integer.parseInt(depCols[i]);
                    }
                } else {
                    // 解析可能的填充值
                    possibleValues.add(line.trim());
                }
            }
        }
    }

    // 执行缺失值填充
    public List<String> fill(String configFilePath, List<String> data) throws IOException {
        try {
            List<String> result = new ArrayList<>();
            if (data == null || data.isEmpty()) {
                return result;
            }

            // 读取配置文件
            List<String> configLines = Files.readAllLines(Paths.get(configFilePath));
            if (configLines.isEmpty() || !configLines.get(0).contains("#")) {
                // 配置文件格式错误，直接返回原始数据
                return data;
            }

            String[] parts = configLines.get(0).split("#");
            if (parts.length < 2) {
                return data;
            }

            String[] dependentIndices = parts[1].split(",");
            if (dependentIndices.length == 0) {
                return data;
            }

            // 获取最大依赖列索引
            int maxIndex = 0;
            for (String idx : dependentIndices) {
                try {
                    int index = Integer.parseInt(idx);
                    if (index > maxIndex) {
                        maxIndex = index;
                    }
                } catch (NumberFormatException e) {
                    // 忽略无效索引
                }
            }

            // 处理每一行数据
            for (String line : data) {
                String[] fields = line.split("\t");
                if (fields.length < 2) {
                    result.add(line);
                    continue;
                }

                String[] values = fields[1].split("\\|");
                if (values.length > maxIndex) {
                    // 模拟填充逻辑：将?替换为"填充值"
                    StringBuilder filledLine = new StringBuilder(fields[0]).append("\t");
                    for (int i = 0; i < values.length; i++) {
                        if ("?".equals(values[i])) {
                            // 这里应根据算法逻辑填充合理值，示例中使用固定值
                            filledLine.append("填充值").append("|");
                        } else {
                            filledLine.append(values[i]).append("|");
                        }
                    }
                    if (filledLine.length() > 0) {
                        filledLine.deleteCharAt(filledLine.length() - 1); // 删除最后一个|
                    }
                    result.add(filledLine.toString());
                    System.out.println("填充后数据行: " + filledLine);
                } else {
                    result.add(line);
                }
            }
            return result;
        } catch (Exception e) {
            // 记录错误并返回原始数据
            System.err.println("填充缺失值时出错: " + e.getMessage());
            return data;
        }
    }

    // 计算概率分布
    private Map<String, Map<String, RelatedInformation>> calculateProbability(List<String> data) {
        Map<String, Map<String, RelatedInformation>> likelihood = new HashMap<>();
        Set<String> prioprob = new HashSet<>();

        for (String row : data) {
            String[] parts = row.split("\t");
            if (parts.length < 2) continue;

            String[] values = parts[1].split("\\|");

            // 跳过表头行
            if (parts[0].equals("0")) continue;

            if (!"?".equals(values[cNo])) {
                // 非缺失值，用于计算先验概率
                String key2 = values[cNo];
                prioprob.add(row);

                for (int i = 0; i < exp.length; i++) {
                    int fNo = exp[i];
                    if (fNo < values.length && !"?".equals(values[fNo])) {
                        String featureKey = fNo + "," + values[fNo];
                        addToLikelihood(likelihood, key2, featureKey, row, false);
                    }
                }
            } else {
                // 缺失值，生成所有可能的填充情况
                for (String possibleValue : possibleValues) {
                    String key2 = possibleValue;

                    for (int i = 0; i < exp.length; i++) {
                        int fNo = exp[i];
                        if (fNo < values.length && !"?".equals(values[fNo])) {
                            String featureKey = fNo + "," + values[fNo];
                            addToLikelihood(likelihood, key2, featureKey, row, true);
                        }
                    }
                }
            }
        }

        // 计算概率
        int total = prioprob.size();
        for (String key2 : likelihood.keySet()) {
            Map<String, RelatedInformation> featureMap = likelihood.get(key2);
            for (String featureKey : featureMap.keySet()) {
                RelatedInformation info = featureMap.get(featureKey);
                float p = (float) info.none_tuple.size() / total;
                if (p == 0.0f) {
                    p = (float) (1.0 / total); // 平滑处理
                }
                info.p = p;
                info.total = total;
            }
        }

        return likelihood;
    }

    private void addToLikelihood(Map<String, Map<String, RelatedInformation>> likelihood,
                                 String key2, String featureKey, String row, boolean isMissing) {
        likelihood.computeIfAbsent(key2, k -> new HashMap<>());
        Map<String, RelatedInformation> featureMap = likelihood.get(key2);

        featureMap.computeIfAbsent(featureKey, k -> new RelatedInformation());
        RelatedInformation info = featureMap.get(featureKey);

        if (isMissing) {
            info.have_tuple.add(row);
            info.flag = true;
        } else {
            info.none_tuple.add(row);
        }
    }

    // 填充缺失值
    private List<String> fillMissingValues(List<String> data,
                                           Map<String, Map<String, RelatedInformation>> likelihood) {
        List<String> result = new ArrayList<>();

        for (String row : data) {
            String[] parts = row.split("\t");
            if (parts.length < 2) {
                result.add(row);
                continue;
            }

            String[] values = parts[1].split("\\|");

            // 复制表头行
            if (parts[0].equals("0")) {
                result.add(row);
                continue;
            }

            if (!"?".equals(values[cNo])) {
                // 非缺失值，直接保留
                result.add(row);
            } else {
                // 缺失值，需要填充
                String bestValue = findBestFillingValue(values, likelihood);
                values[cNo] = bestValue;

                // 重建行数据
                StringBuilder sb = new StringBuilder();
                sb.append(parts[0]).append("\t");
                for (int i = 0; i < values.length; i++) {
                    sb.append(values[i]);
                    if (i < values.length - 1) {
                        sb.append("|");
                    }
                }
                result.add(sb.toString());
            }
        }

        return result;
    }

    // 找到最佳填充值
    private String findBestFillingValue(String[] values,
                                        Map<String, Map<String, RelatedInformation>> likelihood) {
        Map<String, Double> classProbabilities = new HashMap<>();

        // 计算每个可能值的后验概率
        for (String possibleValue : possibleValues) {
            double probability = 1.0;

            // 基于依赖列计算联合概率
            for (int i = 0; i < exp.length; i++) {
                int fNo = exp[i];
                if (fNo < values.length && !"?".equals(values[fNo])) {
                    String featureKey = fNo + "," + values[fNo];

                    // 获取该特征值在可能填充值下的概率
                    Map<String, RelatedInformation> featureMap = likelihood.get(possibleValue);
                    if (featureMap != null && featureMap.containsKey(featureKey)) {
                        probability *= featureMap.get(featureKey).p;
                    } else {
                        // 如果没有统计信息，给一个小概率
                        probability *= 0.01;
                    }
                }
            }

            classProbabilities.put(possibleValue, probability);
        }

        // 找到概率最大的值
        String bestValue = possibleValues.get(0);
        double maxProbability = -1;

        for (Map.Entry<String, Double> entry : classProbabilities.entrySet()) {
            if (entry.getValue() > maxProbability) {
                maxProbability = entry.getValue();
                bestValue = entry.getKey();
            }
        }

        return bestValue;
    }

    // 辅助类：存储特征与类别的关联信息
    public static class RelatedInformation {
        public boolean flag = false;
        public Set<String> none_tuple = new HashSet<>(); // 非缺失值的行
        public Set<String> have_tuple = new HashSet<>();  // 缺失值的行
        public float p;  // 概率
        public int total; // 总行数

        @Override
        public String toString() {
            return "RelatedInformation{" +
                    "flag=" + flag +
                    ", none_tuple.size=" + none_tuple.size() +
                    ", have_tuple.size=" + have_tuple.size() +
                    ", p=" + p +
                    ", total=" + total +
                    '}';
        }
    }
}